Skip to content

fix(formatters/markdown): stop leaking <error:> placeholder into output#2144

Open
tmchow wants to merge 3 commits intolycheeverse:masterfrom
tmchow:osc/2143-error-uri-leak-markdown
Open

fix(formatters/markdown): stop leaking <error:> placeholder into output#2144
tmchow wants to merge 3 commits intolycheeverse:masterfrom
tmchow:osc/2143-error-uri-leak-markdown

Conversation

@tmchow
Copy link
Copy Markdown

@tmchow tmchow commented Apr 16, 2026

Summary

When lychee encounters a link whose URL can't be parsed, the markdown stats formatter was leaking <error:> into the report because the placeholder Uri constructed by lychee_lib::types::request_error has scheme "error" and the formatter always wraps the Uri in <…>. Addresses #2143.

Why

RequestError::into_response (in lychee-lib/src/types/request_error.rs) constructs a synthetic Response for reporting purposes whenever a raw link can't be turned into a valid URL. It uses a single static ERROR_URI: LazyLock<Uri> = LazyLock::new(|| Uri::try_from("error:").unwrap()); as the placeholder, backed by the error: scheme.

The existing markdown formatter treated every response identically:

let mut formatted = format!(
    "* [{}] <{}>",
    response.status.code_as_string(),
    response.uri,
);

For the placeholder, response.uri renders as error:, so the output became:

* [ERROR] <error:> (at 6:14) | Cannot parse 'https://example]org/malformed_two' into a URL: invalid international domain name

That's bad for two reasons: <error:> looks like a clickable anchor pointing at an unresolvable custom scheme, and it visually overshadows the actual failing URL which now only lives in the | details tail.

Changes

  • lychee-bin/src/formatters/stats/markdown.rs:
    • New private constant UNPARSEABLE_URI_SCHEME = "error", kept in lockstep with lychee-lib's placeholder (the comment points back at request_error.rs so it doesn't drift silently).
    • markdown_response now branches: when response.uri.scheme() == UNPARSEABLE_URI_SCHEME, it omits the <uri> segment and emits just * [STATUS]; the subsequent (at span) and | details tail continue to render normally.
    • No behavioural change for any non-placeholder URI -- the old code path remains default.

Testing

  • New test_markdown_response_unparseable_url_omits_uri_segment directly exercises the placeholder path:
    • Constructs a ResponseBody with Uri::try_from("error:") (the same value RequestError::into_response emits).
    • Asserts <error:> is not present in the output.
    • Asserts the prefix stays * [ERROR] so downstream consumers still see the status code.
    • Asserts the span (at 1:1) and the underlying malformed URL text survive in the details tail.
  • cargo test --package lychee --bin lychee -> 78 passed, 0 failed.

Fixes #2143

This contribution was developed with AI assistance (Claude Code).

Compound Engineering

tmchow added 3 commits April 16, 2026 04:11
When lychee cannot parse a link into a URL, lychee-lib substitutes a
placeholder Uri (scheme: "error") via RequestError::into_response.
The markdown formatter always wraps the Uri in <>, so a malformed
link in the input file surfaced as `<error:>` in the report --
burying the actual URL and error under markup noise (lycheeverse#2143).

Detect the placeholder scheme ("error") and skip the <uri> segment
when rendering. The status code, span, and underlying error details
still carry enough information for the reader to find and fix the
malformed link, without the misleading <error:> anchor.

Fixes lycheeverse#2143
Addresses codex:review P3 feedback on PR lycheeverse#2144: the initial check
suppressed the URI for any Uri with scheme 'error', which would also
hide legitimate inputs like 'error:foo'. Narrow to exact sentinel
match via Uri::as_str() == "error:" so the behavior only changes
for the placeholder emitted by RequestError::into_response.

Also add a regression test confirming that non-sentinel URIs with the
'error:' scheme still render their full <uri> segment.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

<error:> leaks into markdown format output for unparseable URLs.

1 participant